﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using WatiN.Core;
using System.Configuration;
using WatiN.Core.Native.InternetExplorer;
using System.IO;
using log4net;
using log4net.Config;
using System.Text.RegularExpressions;

namespace PlayerStat
{
    class ScrapeDenmark : ScrapeSite
    {
        static int tempNumber = 1;
        ILog logger;
        private int leagueID = -1;
        private int maxRound = -1; //set the max round in one season
        private int countryID = -1;

        private string match_url_template = @"http://www.ligafodbold.dk/?cat=statsResultsSeason";
        //private string match_stat_url_template = @"http://soccernet.espn.go.com/match?id={0}&cc=4716";
        //private string player_stat_url_template = @"http://soccernet.espn.go.com/gamecast/statistics?id={0}&cc=4716";
        private string league = string.Empty;

        public ScrapeDenmark()
        {
            leagueID = -1;
            maxRound = 30;
            countryID = Leagues.DenmarkID;

            logger = LogManager.GetLogger("scrape");
            if (logger == null)
            {
                throw new Exception("Null Logger");
            }
        }

        public void SetLeague(int nLeagueID)
        {
            leagueID = nLeagueID;
            switch (leagueID)
            {
                case 16:
                    league = "Superligaen";
                    break;
                default:
                    throw new Exception("Wrong League Number");
            }
        }

        public void SetMaxRound(int nMaxRound)
        {
            maxRound = nMaxRound;
        }

        public void SetMaxRoundBySeason(int year)
        {
            if (year <= 2008) maxRound = 33;
            else maxRound = 33;
        }

        // The Main Function, scrape webs
        public bool Scrape()
        {
            logger.Debug("#Scrape Denmark League# Start");
            IE mainIE = new IE();
            IE statIE = null;
            int iHomePageWaitTime = 5 * 1000; //set the wait time for each web, to avoid unexpected errors 
            int iMatchPageWaitTime = 5 * 1000; //set the wait time for each web, to avoid unexpected errors

            try
            {
                EventInit evnt = new EventInit(leagueID, maxRound,Leagues.DenmarkID.ToString());
                string date = string.Empty;
                int round = 0;
                int year = 2007;
                string url = string.Empty;
                while (evnt.GetEventRound(leagueID, out year, out round, out date))
                {
                    logger.DebugFormat("Go to season {0}, round {1}", year, round);

                    year = 2011;
                    SetMaxRoundBySeason(year);

                    // Get one season's match URL
                    //url = GetAllMatchURL(year, leagueID);
                    //url = GetMatchURL(year, round);
                    url = "E:\\temp\\2011Denmark.htm"; //for local test

                    mainIE.GoTo(url);
                    System.Threading.Thread.Sleep(iHomePageWaitTime);

                    //Get Match Date
                    Table tbl = null;
                    Span[] sc = null;
                    if (!GetMatchTable(mainIE, out sc))
                    {
                        logger.Error("The validated match table is not found.");
                        continue;
                    }

                    DataTable matches = null;
                    //if (!GetMatchList(tbl, year, round, out matches))
                   if (!GetMatchList(sc, year, round, out matches))
                    {
                        logger.ErrorFormat("Parse the match list of round {0} failed.", round);
                        continue;
                    }

                    foreach (DataRow dr in matches.Rows)
                    {
                        MatchData md = new MatchData();
                        md.LeagueID = this.leagueID;
                        md.MatchRound = round;
                        md.matchTime = (DateTime)dr["MatchTime"];
                        md.home = (string)dr["HomeTeam"];
                        md.homeID = (int)dr["HomeID"];
                        md.away = (string)dr["AwayTeam"];
                        md.awayID = (int)dr["AwayID"];
                        md.match.homeScore = (int)dr["HomeScore"];
                        md.match.awayScore = (int)dr["AwayScore"];

                        statIE = new IE();

                        logger.Info("GoTo URL:" + dr["MatchStatURL"].ToString());
                        //statIE.GoTo(dr["MatchStatURL"].ToString()); 
                        statIE.GoTo("e:\\temp\\DenmarkMatch1.htm"); // for local test
                        //statIE.GoTo("e:\\temp\\DenmarkErrorData4.htm"); // for local test

                        System.Threading.Thread.Sleep(iMatchPageWaitTime); // wait a longer time to ensure the table can be loaded correctly

                        // Full Match Stat Scrape, need to implement
                        if (!GetMatchStat(statIE, ref md))
                        {
                            statIE.Close();
                            logger.ErrorFormat("Error to get statistic in {0} vs {1}", md.home, md.away);
                            continue;
                        }
                        statIE.Close();
                        md.SaveToDB();

                    }
                    System.Threading.Thread.Sleep(3 * 1000);
                    evnt.NextRound();
                }
                logger.Debug("#Scrape Denmark League# End");
                return true;
            }
            catch (Exception ex)
            {
                logger.Error("#Scrape Denmark League# Failed: Exception.");
                logger.Error(ex.ToString());
                return false;
            }
            finally
            {
                if (mainIE != null)
                {
                    mainIE.Close();
                }

                if (statIE != null)
                {
                    statIE.Close();
                }
            }
        }

        /// <summary>
        /// Get the match URL for the specified round/season
        /// </summary>
        /// <param name="year">season's start year</param>
        /// <param name="round">round no.</param>
        /// <returns>URL</returns>
        public string GetMatchURL(int year, int round)
        {
            logger.Debug("#GetMatchURL# Starts. [PARAM IN]Year:" + year.ToString() + ". Round:" + round.ToString());
            int iNextYear = year + 1;
            string strYear = year.ToString();
            string strNextYear = iNextYear.ToString().Substring(iNextYear.ToString().Length - 2, 2);
            string strURL = string.Format(match_url_template, strYear, strNextYear, round);
            logger.Debug("#GetAllMatchURL# Ends. [PARAM OUT] URL:" + strURL);

            return strURL;
        }

        /// <summary>
        /// Get the match URL for the all round of specified season
        /// </summary>
        /// <param name="year">season's start year</param>
        /// <returns>URL</returns>
        public string GetAllMatchURL(int year, int leagueID)
        {
            logger.Debug("#GetAllMatchURL# Starts. [PARAM IN]Year:" + year.ToString());

            string strURL = string.Empty;
            switch (leagueID)
            {
                case 16:
                    {
                        league = "Tippeligaen";
                        if (2006 == year) strURL = @"http://www.fotball.no/System-pages/TabellTermin/?tournamentId=82890";
                        else if (2007 == year) strURL = @"http://www.fotball.no/System-pages/TabellTermin/?tournamentId=82864";
                        else if (2008 == year) strURL = @"http://www.fotball.no/System-pages/TabellTermin/?tournamentId=82849";
                        else if (2009 == year) strURL = @"http://www.fotball.no/System-pages/TabellTermin/?tournamentId=37562";
                        else if (2010 == year) strURL = @"http://www.fotball.no/System-pages/TabellTermin/?tournamentId=81239";
                        else if (2011 == year) strURL = @"http://www.ligafodbold.dk/?cat=statsResultsSeason";
                        break;
                    }
                default:
                    throw new Exception("Wrong League Number");
            }

            logger.Debug("#GetAllMatchURL# Ends. [PARAM OUT] URL:" + strURL);

            return strURL;
        }

        /// <summary>
        /// Get a season's all match data into mTable
        /// </summary>
        /// <param name="ie">The ie web which has a season's all match data</param>
        /// <returns>mTable</returns>
        public bool GetMatchTable(IE ie, out Span[] sc)
        {
            logger.Debug("#GetMatchTable# Starts.");

            // ONLY one table here

            Div divMatch = ie.Div(Find.ByClass("articleBox") && Find.ByIndex(0));
            sc = new Span[divMatch.Spans.Count];
            divMatch.Spans.CopyTo(sc, 0);

            // Out put the Match format to Txt file
            /*
            string path = @"e:\Denmark.txt";
            // This text is added only once to the file.
            if (!File.Exists(path)) 
            {
                int divCount = divMatch.Spans.Count;
                // Create a file to write to.
                using (StreamWriter sw = File.CreateText(path)) 
                {
                    for (int i = 0; i < divCount;i++ )
                    {
                        sw.WriteLine("Line " + i.ToString() + ": " + sc[i].Text );
                    }
                }	
            }   
            */

            if ( !sc[0].Text.Contains("Superligaen") )
            {
                logger.Debug("#GetMatchTable# Ends. Return:false.");
                return false;
            }
            else
            {
                logger.Debug("#GetMatchTable# Ends. Return:true.");
                return true;
            }
        }

        /// <summary>
        /// Scrape the Matches List of each round
        /// </summary>
        /// <param name="sc">The Spans which has a season's all match data</param>
        /// <param name="year">The specified season, different season may have different team account</param>
        /// <param name="round">The specified round</param>
        /// <returns>mTable</returns>
        public bool GetMatchList(Span[] sc, int year, int round, out DataTable mTable)
        {
            logger.Debug("#GetMatchList# Starts. Round:" + round.ToString());
           
            try
            {
                mTable = new DataTable();
                if (round > maxRound)
                {
                    logger.Debug("#GetMatchList# Ends. Return:true.");
                    return true;
                }

                mTable.Columns.Add("MatchTime", typeof(DateTime));
                mTable.Columns.Add("HomeTeam", typeof(string));
                mTable.Columns.Add("HomeID", typeof(int));
                mTable.Columns.Add("HomeScore", typeof(int));
                mTable.Columns.Add("AwayTeam", typeof(string));
                mTable.Columns.Add("AwayID", typeof(int));
                mTable.Columns.Add("AwayScore", typeof(int));
                mTable.Columns.Add("MatchStatURL", typeof(string));

                DateTime dtPreTime = DateTime.Parse("9999/12/31");
                int iMatchesPerRound = 0;
                int iSpansPerMatch = 7;
                int iSpansOffsetPerRound = 3;
                int iSpansPerRound = 0;
                int i = 0;

                if (year <= 2008)
                {
                    iMatchesPerRound = 6;
                }
                else
                {
                    iMatchesPerRound = 6;
                }

                iSpansPerRound = iMatchesPerRound * iSpansPerMatch + iSpansOffsetPerRound;
                i = 2 + (round - 1) * iSpansPerRound; // add 2 for round title, 45 line each round

                while (i < sc.Length)
                {
                    string strRoundTitle = sc[i].Text;

                    #region generate match data
                    if (strRoundTitle.Contains(round.ToString() + ". spillerunde")) // the specified round
                    {
                        #region add each match data for specified round
                        for (int j = 0; j < iMatchesPerRound; j++)
                        {
                            DataRow dr = mTable.NewRow();

                            DateTime dtMatchTime;
                            string strHomeTeam = "";
                            string strAwayTeam = "";
                            int iHomeScore = -1;
                            int iAwayScore = -1;
                            string strMatchURL = "";

                            if (sc[i+j+iSpansOffsetPerRound].Text.Trim() != string.Empty) // Match Time
                            {
                                string strDateTime = sc[i + j * iSpansPerMatch + iSpansOffsetPerRound].Text.Trim();
                                dtPreTime = Translate.TransDenmarkDateTime(strDateTime);
                            }
                            dtMatchTime = dtPreTime;

                            string[] tempTeams = sc[i + j * iSpansPerMatch + iSpansOffsetPerRound + 1].Text.Split('-');
                            if (tempTeams.Length != 2)
                            {
                                throw new Exception("Can not parse teams. Round:" + round.ToString() + "." );
                            }
                            else 
                            {
                                strHomeTeam = tempTeams[0].Trim();
                                strAwayTeam = tempTeams[1].Trim();
                            }

                            iHomeScore = int.Parse(sc[i + j * iSpansPerMatch + iSpansOffsetPerRound + 2].Text.Trim());
                            iAwayScore = int.Parse(sc[i + j * iSpansPerMatch + iSpansOffsetPerRound + 4].Text.Trim());
                            strMatchURL = sc[i + j * iSpansPerMatch + iSpansOffsetPerRound + 1].Links.First().Url;

                            dr["MatchTime"] = dtMatchTime;
                            dr["HomeTeam"] = strHomeTeam;
                            //dr["HomeID"] = GetID(tr.TableCells[1].Links[0].Url);
                            dr["HomeID"] = -1;
                            dr["HomeScore"] = iHomeScore;
                            dr["AwayTeam"] = strAwayTeam;
                            //dr["AwayID"] = GetID(tr.TableCells[3].Links[0].Url);
                            dr["AwayID"] = -1;
                            dr["AwayScore"] = iAwayScore;
                            dr["MatchStatURL"] = strMatchURL;
                            mTable.Rows.Add(dr);
                        }
                        #endregion add each match data for specified round

                        break;
                    }
                    #endregion generate match data

                    i += iSpansPerRound;
                }

                logger.Debug("#GetMatchList# Ends. Return:true.");
                return true;
            }
            catch (Exception ex)
            {
                logger.Error("#GetMatchList# Failed: Exception.");
                logger.Error(ex.ToString());
                mTable = null;

                logger.Debug("GetMatchTable Ends. Return:false.");
                return false;
            }
        }

        // Get the playerID
        private int GetPlayerID(string str)
        {
            string temp1 = str.Remove(0, @"http://www.ligafodbold.dk/?cat=statsPlayerView&cat_id=1&pID=".Length);
            string temp = temp1.Remove(temp1.IndexOf("&tID=163"), @"&tID=163".Length);
            try 
            {
                return int.Parse(temp);
            }
            catch (Exception ex)
            {
                logger.Warn("#GetPlayerID# Invalid data source." + ex.ToString());               
                return 0;
            }         
        }

        /// <summary>
        /// Scrape each match's statistic
        /// </summary>
        /// <param name="tbl">The table which has a season's all match data</param>
        /// <param name="round">The specified round</param>
        /// <returns>mTable</returns>
        private bool GetMatchStat(IE ie, ref MatchData md)
        {
            logger.Debug("#GetMatchStat# Starts.");
            try
            {
                //Div divMatch = ie.Div(Find.ByClass("matchInfo_teamBox") && Find.ByIndex(0));
                //Span[] sc = new Span[divMatch.Spans.Count];
                //divMatch.Spans.CopyTo(sc, 0);

                Div divHomePlayers = ie.Div(Find.ByClass("matchInfo_teamBox") && Find.ByIndex(0));
                Div divAwayPlayers = ie.Div(Find.ByClass("matchInfo_teamBox") && Find.ByIndex(1));

                if (!divHomePlayers.Exists 
                    || !divAwayPlayers.Exists )
                {
                    throw new Exception("The table of team data is not found");
                }

                if (false == GetTeamStat(divHomePlayers, true, ref md.match, ref md.homeplayers) || // get home team's match statistic
                    false == GetTeamStat(divAwayPlayers, false, ref md.match, ref md.awayplayers)) // get away team's match statistic
                {
                    logger.Debug("#GetMatchStat# Ends. Return:false.");
                    return false;
                }

                Div divMatch = ie.Div(Find.ByClass("articleBox") && Find.ByIndex(0));
                if (false == GetGoalStat(divMatch, ref md.match, ref md.homeplayers, ref md.awayplayers) ) // get home team's match statistic
                {
                    logger.Debug("#GetMatchStat# Ends. Return:false.");
                    return false;
                }

                logger.Debug("#GetMatchStat# Ends. Return:true");
                return true;

                /*
                Table tblHomeGoals = ie.Tables[2];
                Table tblAwayGoals = ie.Tables[3];
                Table tblHomeSubs = ie.Tables[4];
                Table tblAwaySubs = ie.Tables[5];
                Table tblHomeCards = ie.Tables[6];
                Table tblAwayCards = ie.Tables[7];

                if (!tblHomePlayers.Exists 
                    || !tblAwayPlayers.Exists 
                    || !tblHomeGoals.Exists
                    || !tblAwayGoals.Exists
                    || !tblHomeSubs.Exists
                    || !tblAwaySubs.Exists
                    || !tblHomeCards.Exists
                    || !tblAwayCards.Exists)
                {
                    throw new Exception("The table of team data is not found");
                }

                if (false == GetTeamStat(tblHomePlayers,tblHomeSubs, true, ref md.match, ref md.homeplayers) || // get home team's match statistic
                    false == GetTeamStat(tblAwayPlayers,tblAwaySubs, false, ref md.match, ref md.awayplayers)) // get away team's match statistic
                {
                    logger.Debug("#GetMatchStat# Ends. Return:false.");
                    return false;
                }

                //old
                if (false == GetPlayerStat(tblHomeGoals, tblHomeCards, true, ref md.match, ref md.homeplayers, ref md.awayplayers) || // get home team's match statistic
                    false == GetPlayerStat(tblAwayGoals, tblAwayCards, false, ref md.match, ref md.awayplayers, ref md.homeplayers)) // get away team's match statistic
                {
                    logger.Debug("#GetMatchStat# Ends. Return:false.");
                    return false;
                }

                logger.Debug("#GetMatchStat# Ends. Return:true");
                return true;
                */
            }
            catch (Exception ex)
            {
                logger.Error("#GetMatchStat# Failed: Exception");
                logger.Error(ex.ToString());

                logger.Debug("#GetMatchStat# Ends. Return:false.");
                return false;
            }
        }

        private bool GetTeamStat(Div divPlayers, bool isHomeTeam, ref MatchStat match, ref Dictionary<int, PlayerStat> players)
        {
            logger.Debug("#GetTeamStat# Starts.");

            try
            {
                Span[] sc = new Span[divPlayers.Spans.Count];
                divPlayers.Spans.CopyTo(sc, 0);

                int iCount = 0;
                int iLineupCount = 0;

                int iSpansPerPlayer = 4;
                int iPlayerCount = divPlayers.Spans.Count / iSpansPerPlayer;

                // for Line-up
                //foreach (Span span in sc)
                for (int i = 0; i < iPlayerCount; i++ )
                {
                    if (iCount >= iPlayerCount)
                    {
                        break;
                    }

                    iCount++;
                    iLineupCount++;

                    int number = GenPlayerNumber();
                    PlayerStat player = new PlayerStat();
                    player.playerName = GetSafeString(sc[iSpansPerPlayer*i].Text.Trim());
                    if (!player.playerName.Equals(string.Empty))
                    {
                        string strPlayerURL = sc[iSpansPerPlayer * i].Links.First().Url;
                        player.playerID = GetPlayerID(strPlayerURL);
                    }

                    //if (iLineupCount > 11) player.isPlayerSub = true;
                    //else player.isPlayerSub = false;

                    player.isPlayerSub = false;
                    player.isSwitchOut = false;

                    // sub or switchout info
                    if (sc[iSpansPerPlayer * i+3].Images.Count != 0)
                    {
                        string strItemType = sc[iSpansPerPlayer * i+3].Images[0].Src;
                        if (strItemType.Contains("subIn.gif")) player.isPlayerSub = true;
                        if (strItemType.Contains("subOut.gif")) player.isSwitchOut = true;
                    }

                    // card info
                    if (sc[iSpansPerPlayer * i + 2].Images.Count != 0)
                    {
                        string strItemType = sc[iSpansPerPlayer * i + 2].Images[0].Src;
                        if (strItemType.Contains("yellowCard.gif"))
                        {
                            player.yellowCard++;
                            if (isHomeTeam) match.homeYCard++;
                            else match.awayYCard++;
                        }

                        if (strItemType.Contains("redCard.gif"))
                        {
                            player.redCard++;
                            if (isHomeTeam) match.homeRCard++;
                            else match.awayRCard++;
                        }
                    }

                    players.Add(number, player);
                }

                //add Marking Info
                foreach (KeyValuePair<int, PlayerStat> kv in players)
                {
                    kv.Value.markID = Marking.GetMarkingID(kv.Value.isPlayerSub, kv.Value.isSwitchOut);
                }
                                
                logger.Debug("#GetTeamStat# Ends. Return:true.");
                return true;
            }
            catch (Exception ex)
            {
                logger.Error("#GetTeamStat# Failed: Exception");
                logger.Error(ex.ToString());

                logger.Debug("#GetTeamStat# Ends. Return:false.");
                return false;
            }
        }

        private bool GetGoalStat(Div divMatch, ref MatchStat match, ref Dictionary<int, PlayerStat> players, ref Dictionary<int, PlayerStat> rivalPlayers)
        {
            try
            {
                logger.Debug("#GetGoalStat# Starts.");
                Span[] sc = new Span[divMatch.Spans.Count];
                divMatch.Spans.CopyTo(sc, 0);

                #region get the score info
                for (int i = 0; i < sc.Length; i++ )
                {
                    Span span = sc[i];
                    if (span.Images.Count != 0)
                    {
                        string strItemType = span.Images[0].Src;
                        if (strItemType.Contains("scoring.gif"))
                        {
                            foreach (KeyValuePair<int, PlayerStat> kv in players)
                            {
                                if (span.Text == kv.Value.playerName)
                                {
                                    kv.Value.goal++;

                                    MinuteStat ms = new MinuteStat();
                                    ms.goalMin = Int32.Parse(sc[i+2].Text.Replace('\'',' ').Trim());

                                    ms.isOwnGoal = false;
                                    ms.name = kv.Value.playerName;
                                    kv.Value.MinStat.Add(ms);

                                    break;
                                }
                            }

                            foreach (KeyValuePair<int, PlayerStat> kv in rivalPlayers)
                            {
                                if (span.Text == kv.Value.playerName)
                                {
                                    kv.Value.goal++;

                                    MinuteStat ms = new MinuteStat();
                                    ms.goalMin = Int32.Parse(sc[i + 2].Text.Replace('\'', ' ').Trim());

                                    ms.isOwnGoal = false;
                                    ms.name = kv.Value.playerName;
                                    kv.Value.MinStat.Add(ms);

                                    break;
                                }
                            }
                        }
                    }
                }
                #endregion get the score info

                return true;
            }
            catch (Exception ex)
            {
                logger.Error("#GetGoalStat# Failed: Exception");
                logger.Error(ex.ToString());

                logger.Debug("#GetGoalStat# Ends. Return:false.");
                return false;
            }
        }

        public int GenPlayerNumber()
        {
            return ((tempNumber++) % 30);
            //try
            //{
            //    return int.Parse(str);
            //}
            //catch (Exception ex)
            //{
            //    return -1 * ((tempNumber++) % 30);
            //}
        }

        private string GetSafeString( string str)
        {
            return ((string.IsNullOrWhiteSpace(str)) ? string.Empty : str.Trim());            
        }
    }
}
